/*
 * Copyright 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0

 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.util.compat;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
  
  public static final String helpmsg = 
      "Google Java API Compatibility Validator 1.0.0\n" +
      "Usage: \n java -jar japicv.jar [-w exceptionsfile] name1 name2\n" +
      "where nameN is a directory, a .jar file, or a .java file";
  
  public static void main(String args[]) throws IOException {
    
    if (args.length == 0) {
      System.out.println(helpmsg);
      return;
    }
    
    File exclusions = null;
    int index = 0;
    
    if (args[0].equals("-w")) {
      exclusions = new File(args[1]);
      if (!exclusions.exists())
        throw new IOException("File " + exclusions.getCanonicalPath() + " does not exist.");
      index += 2;
    }
    
    File file1 = new File(args[index]);
    if (!file1.exists())
      throw new IOException("File " + file1.getCanonicalPath() + " does not exist.");
    File file2 = new File(args[++index]);
    if (!file2.exists())
      throw new IOException("File " + file2.getCanonicalPath() + " does not exist.");
    
    List<ClassNode> classes1, classes2;
    
    if (exclusions != null) {
      List<ClassNode> excludedClasses = new ArrayList<ClassNode>();
      List<String> excludedPkgs = new ArrayList<String>();
      parseExclusions(exclusions, excludedClasses, excludedPkgs);
      classes1 = CoreExtractorAST.extract(file1, excludedClasses, excludedPkgs);
      classes2 = CoreExtractorAST.extract(file2, excludedClasses, excludedPkgs);
    }
    else {
      classes1 = CoreExtractorAST.extract(file1);
      classes2 = CoreExtractorAST.extract(file2);
    }
    
    String ret = APIComparator.compareLists(classes1, classes2);
    System.out.println(ret);
    if (!ret.equals(""))
      System.exit(1);
  }
  
  public static void parseExclusions(File filename, List<ClassNode> retValue,
      List<String> pkgs) throws IOException {
    
    Scanner scanner = new Scanner(filename);
    if (!scanner.hasNext())
      throw new IOException("Whitelist file is empty.");
    String keyword = scanner.next();
    ClassNode current = null;
    while (scanner.hasNext()) {
      if (!keyword.equals("package"))
        throw new IOException("Whitelist parse error: \"" + keyword + "\" is not a valid keyword.");
      String pkgname = scanner.next();
      pkgs.add(pkgname);
      if (scanner.hasNext())
        keyword = scanner.next();
      while (scanner.hasNext())
        if (!keyword.equals("class"))
          break;
        else {
          String classname = scanner.next();
          current = new ClassNode(pkgname, classname);
          retValue.add(current);
          pkgs.remove(pkgname);
          if (scanner.hasNext())
            keyword = scanner.next();
          while (scanner.hasNext())
            if (keyword.equals("field")) {
              current.addField(new FieldNode(scanner.next()));
              if (scanner.hasNext())
                keyword = scanner.next();
            }
            else if (keyword.equals("method")) {
              String methodname = scanner.next();
              List<FieldNode> params = new ArrayList<FieldNode>();
              MethodNode method = new MethodNode(methodname, null, null, params);
              current.addMethod(method);
              if (scanner.hasNext())
                keyword = scanner.next();
              while (scanner.hasNext())
                if (keyword.equals("paramtype")) {
                  params.add(new FieldNode(null, scanner.next(), null));
                  if (scanner.hasNext())
                    keyword = scanner.next();
                }
                else if (keyword.equals("exception")) {
                  method.addException(scanner.next());
                  if (scanner.hasNext())
                    keyword = scanner.next();
                }
                else break;
            }
            else break;
        }
    }
  }
  
}
